import FormConstant from "./FormConstant";
import Common from "./common";
import { Formula } from './FormulaUtil.js';
var FormulaUtil = Formula;

/**
 * {
    "zibiaoonetoone": {
        "c": "FormulaUtil.SUB_SUM([{zbonetomany.a}])"
    },
    "zbonetomany": {
        "c": "{zbonetomany.a}+{zbonetomany.b}"
    }
}
 * @type {{calcAreas(*, *, *): void, calc: FormCalc.calc}}
 */
var FormCalc = {
  /**
   * 将数据构建成如下的格式
   * [{table"",type:"onetoone",data:[]}]
   * @param formulas
   * @param formData
   * @returns {[]}
   */
  handData(formData){
    //构建数据数组。
    var aryData=[];
    var mainData={table:"main",type:"main",data:formData};
    aryData.push(mainData);
    //处理子表。
    for(var key in formData){
      if(key.startsWith(FormConstant.SubPrefix)){
        var data=formData[key];
        var table=key.replace(FormConstant.SubPrefix ,"");
        var type=(data instanceof  Array)?"onetomany":"onetoone";

        var tableJosn={table:table,type:type,data};

        aryData.push(tableJosn);
      }
    }
    return aryData;
  },
  getData(aryData){
    var data={};
    for(var i=0;i<aryData.length;i++){
      var o=aryData[i];
      data[o.table]=o.data;
    }
    return data;
  },
  getTypeByKey(key,aryData){
    for(var i=0;i<aryData.length;i++){
      var row=aryData[i];
      if(row.table==key){
        return row.type;
      }
    }
    return null;
  },
  getDataByKey(key,aryData){
    for(var i=0;i<aryData.length;i++){
      var row=aryData[i];
      if(row.table==key){
        return row.data;
      }
    }
    return null;
  },
  /**
   * 处理一对多子表。
   * <pre>
   *   1.替换主表的公式字段
   *   2.替换一对一子表的公式字段
   *   3.替换一对多子表字段。
   *  </pre>
   * @param key
   * @param data
   * @param aryData
   */
  handOneToMany(table, formulas,data, aryData){
    var subData=FormCalc.getDataByKey(table,aryData);
    for(var rowField in formulas) {
      var formula = formulas[rowField];
      formula=FormCalc.handRowFormula(formula,aryData).formula;
      for(var i = 0, j = subData.length; i < j; i++) {
        var row = subData[i];
        var val=   eval(formula);
        row[rowField] = val;
      }
    }
  },
  /**
   * 替换子表的公式。
   * @param formula
   * @param aryData
   * @returns {{formula: *, table: *}}
   */
  handRowFormula(formula,aryData){
    var curTable="";
    //主表替换正则  支持子表公式中有主表的字段
    // {(中文)field}
    // {field}
    var mainReg = /\{(\(.*?\)){0,1}(\w*?)\}/g;
    var formula = formula.replace(mainReg, function(a, b, c) {
      return "data.main." + c ;
    });
    //处理一对一的子表
    //获取公式的子表，如果子表属于一对一的子表则进行替换。
    var oneReg = /\{(\(.*?\)){0,1}(\w*?)\.(\w*?)\}/g;
    var match = oneReg.exec(formula);
    while (match != null) {
      var table=match[2];
      var field=match[3];
      var type=FormCalc.getTypeByKey(table,aryData);
      if(type=="onetoone"){
        formula=formula.replace(match[0], function() {
          return "data." + table +"." + field ;
        });
      }
      //是一对多的情况。
      else {
        if(!curTable){
          curTable=table;
        }
      }
      match = oneReg.exec(formula);
    }
    //子表表替换正则
    // 匹配 {(中文)table.field}
    // 匹配 {table.field}
    var rowReg = /\{(\(.*?\)){0,1}(\w*?)\.(\w*?)\}/g;
    formula = formula.replace(rowReg, function(a, b, c, d) {
      return "row." + d + "";
    });
    return {formula:formula,table:curTable};
  },

  /**
   * 处理一对一,一对多的公式。
   * <pre>
   * <pre>
   * @param table     公式所在的表
   * @param formulas  formulas 公式
   * @param data      data {表:数据}
   * @param aryData   [{table:"",type:"",data:[]}]
   */
  handMainOneToOne(table, formulas,data, aryData){
    for(var field in formulas){
      //公式。
      var formula=formulas[field];

      var val=FormCalc.calcFormula(formula,data,aryData);
        if(val!=null){
            data[table][field]=val;
        }
    }
  },
  /**
   * {
   *  //表名:{}
   *   main:{key:{公式}},
   *   contract:{key:公式}
   * }
   * @param formulas
   * @param formData
   */
  calc: function(formulas, formData) {

    //构建数据数组。
    var aryData=FormCalc.handData(formData);


    var data=FormCalc.getData(aryData);
    //计算一对多子表
    for(var key in formulas) {
      var type=FormCalc.getTypeByKey(key,aryData);
      if(type == "main" || type=="onetoone") {
        continue;
      };
      var subFormulas=formulas[key];
      //处理一对多子表的公式。
      this.handOneToMany(key,subFormulas,data,aryData);
    }
    //计算计算主表和一对一子表。
    //{total: "{jine} +FormulaUtil.([{zibiao1.amount}*{zibiao1.price}])"}
    for(var table in formulas) {
      var type = FormCalc.getTypeByKey(table, aryData);
      if (type == "onetomany") {
        continue;
      }
      var formulaObj=formulas[table];
      this.handMainOneToOne(table, formulaObj,data, aryData)
    }


  },
  calcFormula(formula,data,aryData){
    //1. 计算子表集合。
    var regStr = /\[(.*?)\]/g;
    //没有子表。
    var match = regStr.exec(formula);
    var m=1;
    while(match != null) {
      var subFormula = match[1];
      var subAry="subAry_" +m;
      //{formula:"公式",table:""}
      var  rowFormulaObj=FormCalc.handRowFormula(subFormula,aryData);
      var subTable=rowFormulaObj.table;
      var rowFormula=rowFormulaObj.formula;
      //子表数据
      var aryData=data[subTable];
      //子表数组。
      var aryRows=[];
      for(var i = 0,len=aryData.length; i < len;i++){
        //取出一行数据进行计算。
        var row=aryData[i];
        var rowData=eval(rowFormula);
        aryRows.push(rowData);
      }
      data[subAry]=aryRows;
      //将公式 FormulaUtil.SUB_SUM([{table.a}*{onetoone.b}])
      //替换成 FormulaUtil.SUB_SUM(data.subAry_1)
      formula=formula.replace(match[0],"data."+ subAry);
      m++;

      match = regStr.exec(regStr);
    }
    if(!aryData || aryData.length==0) return null;
    //2.替换主表
    var mainReg = /\{(\(.*?\)){0,1}(\w*?)\}/g;
    formula = formula.replace(mainReg, function(a, b, c) {
      return "data.main." + c ;
    });
    //3.替换子表
    var rowReg = /\{(\(.*?\)){0,1}(\w*?)\.(\w*?)\}/g;
    formula = formula.replace(rowReg, function(a, b, c, d) {
      return "data."+c+"." + d ;
    });
    var val=eval(formula);

    return val;
  },
  /**
   * 计算区域。
   * @param calcs
   * @param formData
   * @param vm
   */
  calcAreas(calcs, formData,vm) {
    //构建数据数组。
    var aryData=FormCalc.handData(formData);
    var data=FormCalc.getData(aryData);
    for(var field in calcs){
      //公式。
      var formula=calcs[field];
      var val=FormCalc.calcFormula(formula,data,aryData);
      vm.$set(vm.calcVal,field,val);
    }

  }
}

export  default FormCalc;
